FLex (弹性盒子)
采用 Flex 布局的元素,称为 Flex 容器(flex container),它的所有子元素自动成为容器成员,称为 Flex 项目(flex item)。
重要属性
- 主轴的方向 flex-direction
- 主轴的对齐方式 justify-content
- 交叉轴的对齐方式 align-items
flex container 容器属性
- flex-direction,决定主轴上元素的排布方向,有 4 种取值
- row:默认值,主轴为水平方向且起点在左端
- row-reverse:主轴为水平方向且起点在右端
- column:主轴为垂直方向且起点在上方
- column-reverse:主轴为垂直方向且起点在下方
- flex-wrap,定义换行方式,当一条轴线放不下时如何换行,有 3 种取值
- nowrap:默认值,不换行
- wrap:换行
- wrap-reverse:换行且第一行在下方
flex-flow,是 flex-direction 属性和 flex-wrap 属性的简写形式,默认值为 row nowrap(主轴在横轴,不换行)
justify-content 定义了子元素在主轴上的对齐方式。水平对齐
- flex-start 默认值,左对齐,从左至右按顺序排列
- flex-end 右对齐,从右至左按顺序排列
- center 居中排列
- space-between 两端对齐,最左与最右的元素与容器边界无间隔,元素与元素间的距离相等
- space-around 等距对齐,元素两侧间隔相等,元素与元素之间的距离是最两端元素与容器边界距离的 2 倍,
- align-items 定义在交叉轴上的项目如何对齐。垂直对齐
- flex-start 以交叉轴的起点对齐
- flex-end 以交叉轴的终点对齐
- center 以交叉轴的中点对齐
- strench 如果项目未设置高度或设置为 auto,将占满整个容器
- baseline 以项目第一行文字的基线对齐
- align-content 定义了多根轴线的对齐方式。轴线对齐
- flex-start:与交叉轴的起点对齐
- flex-end:与交叉轴的终点对齐
- center:与交叉轴的中点对齐
- space-between:与交叉轴两端对齐,轴线之间的间隔相等
- space-around:轴线之间的间隔相等,轴线间的距离是轴线与交叉轴起点、交叉轴终点距离的两倍。
- stretch:默认值,轴线占满整个交叉轴
flex item 项目属性
- order,定义项目的排列顺序,数值越小,排列越靠前,默认都为 0
- flex-grow,定义项目的放大比例,默认都为 0,即使有剩余空间也不放大。如果都设为 1,则所有项目将等分空间。如果有一个项目设为 2 而其它项目设为 1,则该项目占据的空间是其它项目的 2 倍。
- flex-shrink,定义了项目的缩小比例,默认都为 1, 既当空间不足时,所有项目都将等比例缩小。如果设为 0,则当空间不足时,该项目也不缩小。
- flex-basis,定义项目占据的主轴空间,浏览器根据这个属性计算是否有多余空间。默认值为 auto,即项目本来的大小,也可设置固定空间。
- flex,是 flex-grow、flex-shrink 和 flex-basis 的简写,默认为 0 1 auto。该属性有 2 个快捷值,auto(1 1 auto)和 none(0 0 auto),建议优先使用这 2 个属性,而不是单独写 3 个分离的属性,因为浏览器会推算相关值。
- align-self,允许单个项目能够有和其它项目不一样的对齐方式,可覆盖 align-items 属性。默认值为 auto,表示继承父元素的 align-items 属性。
flex 缩写
flex 是 flex-grow, flex-shrink, flex-basis 的缩写,默认值是 0 1 auto
flex-grow 和 flex-shrink 属性有什么用?
.item {
/* 增长比例,子项合计宽度小于容器宽度,需要根据每个子项设置的此属性比例对剩下的长度进行分配 */
flex-grow: 0;
/* 回缩比例,子项合计宽度大于容器宽度,需要根据每个子项设置的此属性比例对多出的长度进行分配 */
flex-shrink: 1;
/* 设置了宽度跟宽度走,没设置宽度跟内容实际宽度走 */
flex-basis: auto;
}
当 flex 取值为 none,则计算值为 0 0 auto,如下是等同的:
.item {
flex: none;
}
.item {
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
}
当 flex 取值为 auto,则计算值为 1 1 auto,如下是等同的:
.item {
flex: auto;
}
.item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
}
当 flex 取值为一个非负数字,则该数字为 flex-grow 值,flex-shrink 取 1,flex-basis 取 0%,如下是等同的:
.item {
flex: 1;
}
.item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
}
当 flex 取值为一个长度或百分比,则视为 flex-basis 值,flex-grow 取 1,flex-shrink 取 1,有如下等同情况(注意 0% 是一个百分比而不是一个非负数字):
.item-1 {
flex: 0%;
}
.item-1 {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;
}
.item-2 {
flex: 24px;
}
.item-1 {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 24px;
}
当 flex 取值为两个非负数字,则分别视为 flex-grow 和 flex-shrink 的值,flex-basis 取 0%,如下是等同的:
.item {
flex: 2 3;
}
.item {
flex-grow: 2;
flex-shrink: 3;
flex-basis: 0%;
}
当 flex 取值为一个非负数字和一个长度或百分比,则分别视为 flex-grow 和 flex-basis 的值,flex-shrink 取 1,如下是等同的:
.item {
flex: 2333 3222px;
}
.item {
flex-grow: 2333;
flex-shrink: 1;
flex-basis: 3222px;
}
flex-basis 规定的是子元素的基准值。所以是否溢出的计算与此属性息息相关。flex-basis 规定的范围取决于 box-sizing。这里主要讨论以下 flex-basis 的取值情况:
auto:首先检索该子元素的主尺寸,如果主尺寸不为 auto,则使用值采取主尺寸之值;如果也是 auto,则使用值为 content。
content:指根据该子元素的内容自动布局。有的用户代理没有实现取 content 值,等效的替代方案是 flex-basis 和主尺寸都取 auto。
百分比:根据其包含块(即伸缩父容器)的主尺寸计算。如果包含块的主尺寸未定义(即父容器的主尺寸取决于子元素),则计算结果和设为 auto 一样。
举一个不同的值之间的区别:
<div class="parent">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
</div>
<style type="text/css">
.parent {
display: flex;
width: 600px;
}
.parent > div {
height: 100px;
}
.item-1 {
width: 140px;
flex: 2 1 0%;
background: blue;
}
.item-2 {
width: 100px;
flex: 2 1 auto;
background: darkblue;
}
.item-3 {
flex: 1 1 200px;
background: lightblue;
}
</style>
主轴上父容器总尺寸为 600px
子元素的总基准值是:0% + auto + 200px = 300px,其中
- 0% 即 0 宽度
- auto 对应取主尺寸即 100px 故剩余空间为 600px - 300px = 300px
伸缩放大系数之和为: 2 + 2 + 1 = 5
剩余空间分配如下:
item-1 和 item-2 各分配 2/5,各得 120px
item-3 分配 1/5,得 60px 各项目最终宽度为:
item-1 = 0% + 120px = 120px
item-2 = auto + 120px = 220px
item-3 = 200px + 60px = 260px 当 item-1 基准值取 0% 的时候,是把该项目视为零尺寸的,故即便声明其尺寸为 140px,也并没有什么用,形同虚设
而 item-2 基准值取 auto 的时候,根据规则基准值使用值是主尺寸值即 100px,故这 100px 不会纳入剩余空间

flex 常见的布局
/* 上下左右居中 */
.box-center {
display: flex;
justify-content: center;
align-items: center;
}
/* item 两端对齐(左右两端不留空间) */
.item-between {
display: flex;
justify-content: space-between;
}
/* item 两端对齐且上下居中(主轴在横轴) */
.lr-bettem {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
/* item 从左到右排列,且上下居中(主轴在横轴) */
.lr-start {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
/* item 从左到右排列,上下不居中 */
.lr-start2 {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
/* item从右到左排列,且上下居中 */
.lr-end {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
/* item 上下两端对齐(主轴在纵轴) */
.ud-bettem {
display: flex;
flex-direction: column;
justify-content: space-between;
}
Flex 主要用于一维布局,而 Grid 则用于二维布局。
flex 容器中存在两条轴, 横轴和纵轴, 容器中的每个单元称为 flex item。
注意:当设置 flex 布局之后,子元素的 float、clear、vertical-align 的属性将会失效。
flex 布局,固定高度,左边定宽,右边自适应?
flex 布局给父元素设置 display:flex,左边的子元素给个 width:100px,右边的子元素 flex:1
如果子元素不能 100% 继承高度,怎么实现撑满?
这个问题我当时没反应过来面试官的意思,我问了一下是不是要纵轴方向的 flex 布局?后来面试官说 嗯。。也可以,这个过了。我就愣了,回来之后想了一下,不知道是不是说如果子元素无法 100%的继承高度,那是不是可以结合定位的方式,比如父元素 relative,子元素 absolute,然后四个位置都是 0?不知道是不是这个意思~无法考究了
Flex 如何实现上下两行,上行高度自适应,下行高度 200px?
flex-direction: column flex: 1
使用 flex 实现三栏布局,两边固定,中间自适应
这就是圣杯布局,也叫双飞翼布局
- 把 center 放在最前面,优先渲染
- 相对定位 relative 也是可以设置 left,right 等值的
- margin 负值的了解和使用
- float 真的不建议使用
现在的 flex/grid 很轻松就能实现,甚至绝对定位也是很容易实现也更容易理解。
作用:圣杯布局和双飞翼布局解决的问题是一样的,就是两边顶宽,中间自适应的三栏布局,中间栏要在放在文档流前面以优先渲染。
区别:圣杯布局,为了中间 div 内容不被遮挡,将中间 div 设置了左右 padding-left 和 padding-right 后,将左右两个 div 用相对布局 position: relative 并分别配合 right 和 left 属性,以便左右两栏 div 移动后不遮挡中间 div。双飞翼布局,为了中间 div 内容不被遮挡,直接在中间 div 内部创建子 div 用于放置内容,在该子 div 里用 margin-left 和 margin-right 为左右两栏 div 留出位置。
圣杯布局代码:
<body>
<div id="hd">header</div>
<div id="bd">
<div id="middle">middle</div>
<div id="left">left</div>
<div id="right">right</div>
</div>
<div id="footer">footer</div>
</body>
<style>
#hd {
height: 50px;
background: #666;
text-align: center;
}
#bd {
/*左右栏通过添加负的margin放到正确的位置了,此段代码是为了摆正中间栏的位置*/
padding: 0 200px 0 180px;
height: 100px;
}
#middle {
float: left;
width: 100%; /*左栏上去到第一行*/
height: 100px;
background: blue;
}
#left {
float: left;
width: 180px;
height: 100px;
margin-left: -100%;
background: #0c9;
/*中间栏的位置摆正之后,左栏的位置也相应右移,通过相对定位的left恢复到正确位置*/
position: relative;
left: -180px;
}
#right {
float: left;
width: 200px;
height: 100px;
margin-left: -200px;
background: #0c9;
/*中间栏的位置摆正之后,右栏的位置也相应左移,通过相对定位的right恢复到正确位置*/
position: relative;
right: -200px;
}
#footer {
height: 50px;
background: #666;
text-align: center;
}
</style>
双飞翼布局代码:
<body>
<div id="hd">header</div>
<div id="middle">
<div id="inside">middle</div>
</div>
<div id="left">left</div>
<div id="right">right</div>
<div id="footer">footer</div>
</body>
<style>
#hd {
height: 50px;
background: #666;
text-align: center;
}
#middle {
float: left;
width: 100%; /*左栏上去到第一行*/
height: 100px;
background: blue;
}
#left {
float: left;
width: 180px;
height: 100px;
margin-left: -100%;
background: #0c9;
}
#right {
float: left;
width: 200px;
height: 100px;
margin-left: -200px;
background: #0c9;
}
/*给内部div添加margin,把内容放到中间栏,其实整个背景还是100%*/
#inside {
margin: 0 200px 0 180px;
height: 100px;
}
#footer {
clear: both; /*记得清楚浮动*/
height: 50px;
background: #666;
text-align: center;
}
</style>
flex 布局
<head>
<style>
.container {
border: 1px solid black;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.item {
border: 1px solid red;
height: 100%;
}
.left {
width: 100px;
}
.right {
flex: 1;
}
</style>
</head>
<body class="container">
<div class="item left">100px宽</div>
<div class="item right">自适应</div>
</body>
非 flex 布局方式
<html>
<head>
<meta charset="utf-8" />
<title>test.html</title>
<style>
.container {
border: 1px solid black;
width: 100vw;
height: 100vh;
}
.item {
border: 1px solid red;
height: 100%;
}
.left {
float: left;
width: 100px;
}
.right {
margin: 0 0 0 100px;
}
</style>
</head>
<body class="container">
<div class="item left">100px宽</div>
<div class="item right">自适应</div>
</body>
</html>
flex 布局设置 width 无效
flex 布局中存在一些问题,比如无法设置宽度
display: flex;
flex-wrap: nowrap;
设置元素不换行,然后子元素分别设置了 50px 的宽度和高度,但是无法生效,要通过如下方式设置
flex: 0 0 50px;
子元素不能直接设置 width: 50px,需要通过 flex 布局指定宽度,关于里面的具体参数。